package com.pactera.madp.cp.service.impl;

import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.pactera.madp.common.security.util.SecurityUtils;
import com.pactera.madp.cp.api.dto.roomqc.QTRuleDto;
import com.pactera.madp.cp.api.dto.roomqc.RuleTouchDto;
import com.pactera.madp.cp.api.entity.*;
import com.pactera.madp.cp.api.entity.roomqc.ChildRuleEntity;
import com.pactera.madp.cp.api.entity.roomqc.QualityTestingRuleEntity;
import com.pactera.madp.cp.api.entity.roomqc.RuleTouchEntity;
import com.pactera.madp.cp.api.vo.roomqt.QTRuleVo;
import com.pactera.madp.cp.handler.CorpContextHolder;
import com.pactera.madp.cp.mapper.workroom.QualityTestRuleMapper;
import com.pactera.madp.cp.service.*;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

@Service
public class QualityTestingRuleServiceImpl extends ServiceImpl<QualityTestRuleMapper, QualityTestingRuleEntity> implements QualityTestingRuleService {

    @Autowired
    private IWorkEmployeeService workEmployeeService;
    @Autowired
    private ChildRuleService childRuleService;
    @Autowired
    private IWorkRoomService workRoomService;
    @Autowired
    private IWorkContactRoomService workContactRoomService;
    @Autowired
    private RuleTouchService ruleTouchService;
    @Autowired
    private RoleService roleService;

    @Override
    @Transactional
    public Boolean save(QTRuleDto dto) {
        QualityTestingRuleEntity entity = new QualityTestingRuleEntity();
        translation(dto, entity);
        entity.setCorpId(CorpContextHolder.getCorpId());
        this.save(entity);
        List<QTRuleDto.Rule> rules = dto.getRules();
        Integer fid = this.getObj(Wrappers.<QualityTestingRuleEntity>lambdaQuery()
                .orderByDesc(QualityTestingRuleEntity::getCreateTime).last("limit 1"), o -> Integer.parseInt(o.toString()));
        List<ChildRuleEntity> childRuleEntities = new ArrayList<>();
        rules.forEach(f -> {
            ChildRuleEntity childRuleEntity = new ChildRuleEntity();
            childRuleEntity.setTime(f.getTime());
            childRuleEntity.setSendWho(f.getSendWho());
            childRuleEntity.setTimeType(f.getTimeType());
            childRuleEntity.setFid(fid);
            childRuleEntity.setRoleId(f.getRoleId());
            childRuleEntities.add(childRuleEntity);
        });

        return childRuleService.saveBatch(childRuleEntities);
    }

    @Transactional
    @Override
    public Boolean update(QTRuleDto dto) {
        QualityTestingRuleEntity entity = new QualityTestingRuleEntity();
        translation(dto, entity);
        List<Integer> ids = dto.getRules().stream().map(m -> m.getId()).collect(Collectors.toList());
        List<Integer> cids = childRuleService.listObjs(Wrappers.<ChildRuleEntity>lambdaQuery().eq(ChildRuleEntity::getFid, dto.getId()), o -> Integer.parseInt(o.toString()));
        List<Integer> dids = cids.stream().filter(f -> !ids.contains(f)).collect(Collectors.toList());
        if (dids.size() != 0) {
            childRuleService.remove(Wrappers.<ChildRuleEntity>lambdaQuery()
                    .in(ChildRuleEntity::getId, dids));
        }
        this.updateById(entity);
        List<ChildRuleEntity> childRuleEntities = new ArrayList<>();
        List<QTRuleDto.Rule> rules = dto.getRules();
        rules.forEach(f -> {
            ChildRuleEntity childRuleEntity = new ChildRuleEntity();
            childRuleEntity.setId(f.getId());
            childRuleEntity.setTime(f.getTime());
            childRuleEntity.setSendWho(f.getSendWho());
            childRuleEntity.setTimeType(f.getTimeType());
            childRuleEntity.setFid(dto.getId());
            childRuleEntity.setRoleId(f.getRoleId());
            childRuleEntities.add(childRuleEntity);
        });
        return childRuleService.saveOrUpdateBatch(childRuleEntities);
    }

    @Override
    public IPage query(Page page, RuleTouchDto dto) {
        QueryWrapper<QualityTestingRuleEntity> wrapper = new QueryWrapper<>();
        Integer corpId = CorpContextHolder.getCorpId();
        wrapper.eq("corp_id", corpId);
        if (dto.getName()!=null && !dto.getName().equals("")) wrapper.like("name", dto.getName());
        if (dto.getCreator()!=null && !dto.getCreator().equals("")) {
            List<WorkEmployeeEntity> list = workEmployeeService.lambdaQuery().eq(WorkEmployeeEntity::getCorpId, corpId).like(WorkEmployeeEntity::getName, dto.getCreator()).list();
            List<Integer> ids = list.stream().map(m -> m.getId()).collect(Collectors.toList());
            if (ids.size() != 0) wrapper.in("creator_id", ids);
        }
        if (dto.getIsOpen()!=null) wrapper.eq("is_open", dto.getIsOpen());
        if (dto.getStartTime()!=null && !dto.getStartTime().equals("")) wrapper.ge("create_time", dto.getStartTime());
        if (dto.getEndTime()!=null && !dto.getEndTime().equals("")) wrapper.lt("create_time", dto.getEndTime() + " 23:59:59");
        if (dto.getRoomId()!=null) wrapper.like("rooms", ","+dto.getRoomId()+",");
        IPage iPage = this.page(page, wrapper);
        List<QualityTestingRuleEntity> records = iPage.getRecords();
        ArrayList<QTRuleVo> vos = new ArrayList<>();
        records.forEach(f -> {
            QTRuleVo vo = new QTRuleVo();
            BeanUtils.copyProperties(f, vo);
            List<ChildRuleEntity> childRuleEntities = childRuleService.lambdaQuery().eq(ChildRuleEntity::getFid, f.getId()).list();
            List<Integer> childRuleIds = childRuleEntities.stream().map(m -> m.getId()).collect(Collectors.toList());
            if (childRuleIds.isEmpty()){
                return;
            }else {
                // 统计
                Long TodayBegin = DateUtil.beginOfDay(new Date()).toTimestamp().getTime();
                LocalDateTime today = LocalDateTime.ofEpochSecond(TodayBegin / 1000, 0, ZoneOffset.ofHours(8));
                Long weekBegin = DateUtil.beginOfWeek(new Date()).toTimestamp().getTime();
                LocalDateTime week = LocalDateTime.ofEpochSecond(weekBegin / 1000, 0, ZoneOffset.ofHours(8));
                Long monthBegin = DateUtil.beginOfMonth(new Date()).toTimestamp().getTime();
                LocalDateTime month = LocalDateTime.ofEpochSecond(monthBegin / 1000, 0, ZoneOffset.ofHours(8));
                //使用两次
                List<RuleTouchEntity> ruleTouchs = ruleTouchService.lambdaQuery().in(RuleTouchEntity::getRuleId, childRuleIds).orderByDesc(RuleTouchEntity::getMsgId).list();
                //查询msgid指定的msgtime是否超过规定时间统计  周  月

                AtomicReference<Integer> weekTime = new AtomicReference<>(0);
                AtomicReference<Integer> todayTime = new AtomicReference<>(0);
                AtomicReference<Integer> monthTime = new AtomicReference<>(0);
                ruleTouchs.forEach(f1 -> {
                    int i = f1.getCreateTime().compareTo(month);
                    if (i >= 0) {
                        monthTime.getAndSet(monthTime.get() + 1);
                        int i1 = f1.getCreateTime().compareTo(week);
                        if (i1 >= 0) {
                            weekTime.getAndSet(weekTime.get() + 1);
                            int i2 = f1.getCreateTime().compareTo(today);
                            if (i2 >= 0) todayTime.getAndSet(todayTime.get() + 1);
                        }
                    }
                });
                vo.setTodayTime(todayTime.get());
                vo.setWeekTime(weekTime.get());
                vo.setMonthTime(monthTime.get());
                vo.setTotalTime(ruleTouchs.size());
                List<WorkRoomEntity> rooms;
                List<String> roomIds;
                LocalDateTime time = LocalDate.now().atStartOfDay();
                if (f.getRoomIds()!=null && !f.getRoomIds().trim().equals("")) {
                    roomIds = Arrays.asList(f.getRoomIds().split(","));
                    rooms = workRoomService.list(Wrappers.<WorkRoomEntity>lambdaQuery().in(WorkRoomEntity::getId, roomIds));
                    ArrayList<QTRuleVo.Room> finalRooms = new ArrayList<>();
                    //装room信息
                    rooms.forEach(m -> {
                        QTRuleVo.Room room = new QTRuleVo.Room();
                        room.setId(m.getId());
                        room.setName(m.getName());
                        String ownerName = workEmployeeService.getObj(Wrappers.<WorkEmployeeEntity>lambdaQuery().select(WorkEmployeeEntity::getName)
                                .eq(WorkEmployeeEntity::getId, m.getOwnerId()), o -> o.toString());
                        room.setOwner(ownerName);
                        room.setStatus(m.getRoomStatus());
                        Integer employeeNumber = workContactRoomService.lambdaQuery().eq(WorkContactRoomEntity::getRoomId, m.getId()).eq(WorkContactRoomEntity::getContactId, 0).count();
                        Integer peopleNumber = workContactRoomService.lambdaQuery().eq(WorkContactRoomEntity::getRoomId, m.getId()).count();
                        room.setEmployeeNumber(employeeNumber);
                        room.setPeopleNumber(peopleNumber);
                        room.setMaxNumber(m.getRoomMax());
                        finalRooms.add(room);

                        List<ChildRuleEntity> list = childRuleService.lambdaQuery().eq(ChildRuleEntity::getFid, f.getId()).list();
                        AtomicReference<Integer> totalTime = new AtomicReference<>(0);
                        //装统计数据
                        AtomicReference<Long> max = new AtomicReference<>(0l);

                        ruleTouchs.forEach(f2 -> {
                            if (f2.getRoomId().equals(m.getId())){
                                totalTime.updateAndGet(v -> v + 1);
                                if (f2.getCreateTime().isAfter(time)) todayTime.updateAndGet(v -> v + 1);
                            }
                        });
                        // 得到最近的触发时间
                        list.forEach(f1 -> {
                            String msgTime = ruleTouchService.getObj(Wrappers.<RuleTouchEntity>lambdaQuery().select(RuleTouchEntity::getTime).eq(RuleTouchEntity::getRuleId, f1.getId()).orderByDesc(RuleTouchEntity::getTime).last("limit 1"), o -> o.toString());
                            if (msgTime != null) {
                                Long aLong = Long.valueOf(msgTime);
                                if (aLong > max.get()) max.set(aLong);
                            }
                        });
                        //统计群的周月数据
                        getStatistic(room, ruleTouchs);
                        room.setTodayTime(todayTime.get());
                        room.setTotalTime(totalTime.get());
                        if (!max.get().equals(0l)) {
                            SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                            room.setLatestTime(format.format(new Date(max.get())));
                        }
                    });
                    vo.setRooms(finalRooms);
                }
                String creatorName = workEmployeeService.getObj(Wrappers.<WorkEmployeeEntity>lambdaQuery().select(WorkEmployeeEntity::getName)
                        .eq(WorkEmployeeEntity::getId, f.getCreatorId()), o -> o.toString());
                vo.setOwner(creatorName);
                DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
                String format = formatter.format(f.getCreateTime());
                vo.setCreateTime(format);
                ArrayList<QTRuleVo.rule> rules = new ArrayList<>();
                childRuleEntities.forEach(f1 -> {
                    QTRuleVo.rule rule = new QTRuleVo.rule();
                    BeanUtils.copyProperties(f1, rule);
                    List<String> ids = Arrays.asList(f1.getSendWho().split(","));
                    if (ids.size() != 0) {
                        List<String> names = workEmployeeService.listObjs(Wrappers.<WorkEmployeeEntity>lambdaQuery().select(WorkEmployeeEntity::getName).in(WorkEmployeeEntity::getId, ids), o -> o.toString());
                        rule.setNames(names);
                    }
                    if (f1.getRoleId() != null) {
                        rule.setRoleName(roleService.getRoleName(f1.getRoleId()));
                    }
                    rules.add(rule);
                });
                vo.setRules(rules);
                vos.add(vo);
            }
        });
        iPage.setRecords(vos);
        return iPage;
    }

    private void getStatistic(QTRuleVo.Room room, List<RuleTouchEntity> ruleTouchs) {
        Long weekBegin = DateUtil.beginOfWeek(new Date()).toTimestamp().getTime();
        LocalDateTime week = LocalDateTime.ofEpochSecond(weekBegin / 1000, 0, ZoneOffset.ofHours(8));
        Long monthBegin = DateUtil.beginOfMonth(new Date()).toTimestamp().getTime();
        LocalDateTime month = LocalDateTime.ofEpochSecond(monthBegin / 1000, 0, ZoneOffset.ofHours(8));
        Long monthTime =  ruleTouchs.stream().filter(f -> f.getRoomId().equals(room.getId())).filter(f -> f.getCreateTime().isAfter(month)).count();
        Long weekTime = ruleTouchs.stream().filter(f -> f.getRoomId().equals(room.getId())).filter(f -> f.getCreateTime().isAfter(week)).count();
        room.setWeekTime(weekTime.intValue());
        room.setMonthTime(monthTime.intValue());
    }

    private void translation(QTRuleDto dto, QualityTestingRuleEntity entity) {
        Integer logId = SecurityUtils.getUser().getId();
        Integer id = workEmployeeService.getObj(Wrappers.<WorkEmployeeEntity>lambdaQuery()
                .select(WorkEmployeeEntity::getId)
                .eq(WorkEmployeeEntity::getLogUserId, logId), o -> Integer.parseInt(o.toString()));
        BeanUtils.copyProperties(dto, entity);
        entity.setCreatorId(id);

    }
}
